import DT03D5_ASCII
import time
import os
import sys
import psutil
import csv
import numpy as np
import gsw # TEOS-10方法库
import multiprocessing.shared_memory
import pwd
import grp
import threading
import logging
import datetime

latitude = 0.0 # 海水的纬度,度点度

Depth_Datafolder = 'Data/Depth/'
formatted_time = time.strftime('%Y%m%d%H%M%S',time.localtime())
Depth_data_file = Depth_Datafolder + f'Depth_data_{formatted_time}.csv'

# 进程查询，防止多运行
def checkProcess(processName):
    # processName = os.path.basename(__file__)
    print("进程查询：{}".format(processName))
    ps1=psutil.pids()
    curps=os.getpid()
    for pid in ps1:
        try:
            cmdline = psutil.Process(pid).cmdline()
        except psutil.NoSuchProcess:
            continue
        # print(cmdline)
        if processName in cmdline and pid != curps and pid != (curps - 1):
            print(f"{processName}:, This is the second process pid = {str(pid)}, so exit!")
            sys.exit(1)
    print(f"进程查询完毕, 无抢占运行情况, now runing {processName},current pid = "+str(curps))
    return

def checkLastCallTime():
    global last_call_time
    time.sleep(30)  # 先等待30秒，使其数据稳定
    while True:
        if time.time() - last_call_time > 10:  # Adjust the time threshold as needed
            subProcStatus[0] = 0x09
        time.sleep(1)  # Adjust the sleep interval as needed

def updateData(DeviceModel):
    global last_call_time
    last_call_time = time.time()
    depth = gsw.z_from_p(DeviceModel.get("pressure") / 100.0,latitude)
    DATA = np.array([last_call_time, DeviceModel.get("temperature"), DeviceModel.get("pressure"), round(depth, 3)])
    # print(DATA)
    with open(Depth_data_file, "a") as f:
        writer = csv.writer(f)
        writer.writerow(DATA)
    # print(DeviceModel.deviceName + " : " + DeviceModel.deviceData)

def idCheck(DeviceModel, devID, code = 0x00):
    global subProcStatus
    logging.basicConfig(filename='Data/log.txt', level=logging.INFO, filemode='w')
    if devID == DeviceModel.ADDR and code == 0x00:
        subProcStatus[0] = 0x10    # 初始化成功
        logging.info(f"{datetime.datetime.now()} - {DeviceModel.deviceName} : 设备自检正常")
        print("{} : 设备自检正常".format(DeviceModel.deviceName))
    elif devID != DeviceModel.ADDR and code == 0x00:
        subProcStatus[0] = 0x01    # 初始化失败
        logging.info(f"{datetime.datetime.now()} - {DeviceModel.deviceName} : 设备自检失败")
        print("{} : 设备自检失败".format(DeviceModel.deviceName))
    elif code == 0x02:
        subProcStatus[0] = 0x02    # 设备丢失
        logging.info(f"{datetime.datetime.now()} - {DeviceModel.deviceName} : 设备串口 {DeviceModel.serialConfig.portName} 丢失")
        print("{} : 设备串口 {} 丢失".format(DeviceModel.deviceName,DeviceModel.serialConfig.portName))
    elif code == 0x0a:
        subProcStatus[0] = 0x0a    # 未知错误
        logging.info(f"{datetime.datetime.now()} - {DeviceModel.deviceName} : 设备串口未知错误")
        print("{} : 设备串口未知错误".format(DeviceModel.deviceName))


if __name__ == "__main__":
    
    _fileName = sys.argv[1]
    checkProcess(_fileName)

    global shared_memory
    global subProcStatus
    if _fileName != "test" and _fileName != "i":
        # 从命令行参数中获取共享内存名称
        shared_memory_name = sys.argv[2]
        # 在子进程中打开共享内存
        shared_memory = multiprocessing.shared_memory.SharedMemory(name = shared_memory_name)
        # 将共享内存映射到一个 NumPy 数组
        subProcStatus = np.ndarray((1,), dtype=np.int32, buffer=shared_memory.buf)
        print("{} : 读取共享内存,当前预设状态为 : {}".format(sys.argv[0], subProcStatus[0]))
    else:
        subProcStatus = 0

    if not os.path.exists(Depth_Datafolder):
        os.makedirs(Depth_Datafolder)
    with open(Depth_data_file, "a") as f:
        writer = csv.writer(f)
        writer.writerow(["Time","temperature","pressure","depth"])

    """设置文件的权限和所有者"""
    uid = pwd.getpwnam('pi').pw_uid  # 获取 pi 用户的用户ID
    gid = grp.getgrnam('pi').gr_gid  # 获取 pi 用户的组ID
    # 修改目录权限，使 pi 用户可以读、写、执行
    os.chmod(os.path.dirname(Depth_Datafolder), 0o777)
    # 更改目录的所有者为 pi 用户
    os.chown(os.path.dirname(Depth_Datafolder), uid, gid)
    os.chmod(Depth_data_file, 0o666)       # 所有人可读写
    os.chown(Depth_data_file, uid, gid)    # 更改所有者为 pi 用户
    
    # 拿到设备模型 Get the device model
    device = DT03D5_ASCII.DeviceModel("DT03D5 Depth Sensor", "/dev/ttyACM1", 115200, 0x01, updateData, idCheck)
    # 开启设备 Turn on the device
    if not device.openDevice():
        idCheck(device, -1) # 反正自检失败就完了
        # time.sleep(5)  # 等待主线程响应
        print("{} : 端口 {} 打开失败, 退出!".format(device.deviceName, device.serialPort))
        # 在主程序退出时手动清理资源
        sys.exit(1)
    
    # 读取设备ID，尝试通信
    while subProcStatus[0] != 0x10: # 如果读取设备ID不正常，就一直读取
        device.readSensor_ID()
        time.sleep(0.1) # 需要时间切换读写
    
    # 开启轮询 Enable loop reading
    device.startLoopRead()

    # 开启时间检查线程
    last_call_thread = threading.Thread(target=checkLastCallTime)
    last_call_thread.start()

    # 读取寄存器 从0x3a读取1个寄存器 Read Register Read 1 register from 0x3a
    # device.readReg(0x3a, 1)
    # 获得读取结果 Obtaining read results
    # device.get(str(0x3a))

    # 写入寄存器 向0x65写入50 即修改检测周期为50hz Write a register to 0x65 and write 50 to modify the detection cycle to 50Hz
    # device.writeReg(0x65, 50)